import { promises as fs } from 'fs';
import hljs from 'highlight.js';
import type MarkdownIt from 'markdown-it';
import path from 'path';
import { createChildLogger } from '../../utils/logger.js';
import { DocumentBrowserManagerPuppeteer } from './browser-manager-puppeteer.js';
import { LocalMermaidManager } from './mermaid-local.js';
import type { ConversionOptions, ConversionResult, PdfOptions } from './types.js';

/**
 * Markdown转PDF工具类
 * 支持中文字体、代码高亮、Mermaid图表
 */
export class MarkdownToPdf {
  private log = createChildLogger('convert/markdown-to-pdf');
  private options: Required<PdfOptions> & {
    chineseFont: string;
    mermaidTheme: string;
  };
  private md!: MarkdownIt;
  private browserManager: DocumentBrowserManagerPuppeteer;

  constructor(options: PdfOptions & { chineseFont?: string; mermaidTheme?: string } = {}) {
    this.options = {
      // 默认配置
      format: 'A4',
      margin: {
        top: '1in',
        right: '0.8in',
        bottom: '1in',
        left: '0.8in',
      },
      displayHeaderFooter: false,
      printBackground: true,
      preferCSSPageSize: true,
      landscape: false,
      // 中文字体配置
      chineseFont: 'PingFang SC, Microsoft YaHei, SimSun, sans-serif',
      // Mermaid配置
      mermaidTheme: 'default',
      ...options,
    };

    // 初始化浏览器管理器（可通过环境变量 BROWSER_ENGINE=puppeteer 切换）
    this.browserManager = new DocumentBrowserManagerPuppeteer();

    // 动态导入markdown-it
    this.initializeMarkdownIt();
  }

  private async initializeMarkdownIt(): Promise<void> {
    const MarkdownItClass = (await import('markdown-it')).default;

    this.md = new MarkdownItClass({
      html: true,
      linkify: true,
      typographer: true,
      highlight: this.highlightCode.bind(this),
    });

    // 自定义渲染器处理Mermaid
    this.setupMermaidRenderer();
  }

  /**
   * 代码高亮处理
   */
  private highlightCode(str: string, lang: string): string {
    if (lang === 'mermaid') {
      return `<div class="mermaid">${str}</div>`;
    }

    if (lang && hljs.getLanguage(lang)) {
      try {
        return `<pre class=\"hljs\"><code class=\"language-${lang}\">${
          hljs.highlight(str, { language: lang }).value
        }</code></pre>`;
      } catch (err) {
        this.log.warn(
          `代码高亮失败 (${lang}): ${err instanceof Error ? err.message : String(err)}`
        );
      }
    }

    return `<pre class="hljs"><code>${this.escapeHtml(str)}</code></pre>`;
  }

  /**
   * HTML转义
   */
  private escapeHtml(unsafe: string): string {
    return unsafe
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#039;');
  }

  /**
   * 设置Mermaid渲染器
   */
  private setupMermaidRenderer(): void {
    if (!this.md) return;

    // 捕获fence块中的mermaid内容
    const defaultFence = this.md.renderer.rules.fence;
    this.md.renderer.rules.fence = (
      tokens: any[],
      idx: number,
      options: any,
      env: any,
      self: any
    ) => {
      const token = tokens[idx];
      if (token?.info?.trim() === 'mermaid') {
        return `<div class="mermaid">${token.content}</div>`;
      }
      return defaultFence ? defaultFence(tokens, idx, options, env, self) : '';
    };
  }

  /**
   * 生成PDF样式
   */
  private generateStyles(): string {
    return `
      <style>
        /* 移除外部CDN依赖，使用内联的简化代码高亮样式，避免网络请求带来的不确定性 */
        .hljs { background: #f6f8fa; color: #24292e; }
        .hljs-keyword, .hljs-selector-tag, .hljs-subst { color: #cf222e; font-weight: 600; }
        .hljs-string, .hljs-title, .hljs-name, .hljs-type, .hljs-attribute { color: #0a3069; }
        .hljs-number, .hljs-literal, .hljs-symbol, .hljs-bullet { color: #0550ae; }
        .hljs-comment { color: #6e7781; font-style: italic; }
        
        * {
          box-sizing: border-box;
        }
        
        body {
          font-family: ${this.options.chineseFont};
          font-size: 14px;
          line-height: 1.6;
          color: #333;
          margin: 0;
          padding: 0;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }

        /* 中文字体优化 */
        .chinese {
          font-family: ${this.options.chineseFont};
        }

        /* 标题样式 */
        h1, h2, h3, h4, h5, h6 {
          font-family: ${this.options.chineseFont};
          margin: 24px 0 16px 0;
          font-weight: 600;
          line-height: 1.25;
          page-break-after: avoid;
        }
        
        h1 { font-size: 2em; border-bottom: 1px solid #eaecef; padding-bottom: 10px; }
        h2 { font-size: 1.5em; border-bottom: 1px solid #eaecef; padding-bottom: 8px; }
        h3 { font-size: 1.25em; }
        h4 { font-size: 1em; }
        h5 { font-size: 0.875em; }
        h6 { font-size: 0.85em; color: #6a737d; }

        /* 段落和列表 */
        p {
          margin: 16px 0;
          orphans: 3;
          widows: 3;
        }

        ul, ol {
          padding-left: 2em;
          margin: 16px 0;
        }

        li {
          margin: 4px 0;
        }

        /* 代码样式 */
        code {
          font-family: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', Consolas, 'Courier New', monospace;
          font-size: 85%;
          background-color: rgba(27,31,35,0.05);
          padding: 0.2em 0.4em;
          border-radius: 3px;
        }

        pre {
          font-family: 'SF Mono', Monaco, Inconsolata, 'Roboto Mono', Consolas, 'Courier New', monospace;
          font-size: 85%;
          background-color: #f6f8fa;
          border-radius: 6px;
          padding: 16px;
          overflow-x: auto;
          margin: 16px 0;
          page-break-inside: avoid;
        }

        pre code {
          background-color: transparent;
          padding: 0;
          border-radius: 0;
          font-size: inherit;
        }

        /* 表格样式 */
        table {
          border-collapse: collapse;
          width: 100%;
          margin: 16px 0;
          page-break-inside: avoid;
        }

        th, td {
          border: 1px solid #d0d7de;
          padding: 8px 12px;
          text-align: left;
          font-family: ${this.options.chineseFont};
        }

        th {
          background-color: #f6f8fa;
          font-weight: 600;
        }

        tr:nth-child(2n) {
          background-color: #f6f8fa;
        }

        /* 引用样式 */
        blockquote {
          margin: 16px 0;
          padding: 0 1em;
          color: #6a737d;
          border-left: 4px solid #d0d7de;
        }

        /* 链接样式 */
        a {
          color: #0969da;
          text-decoration: none;
        }

        a:hover {
          text-decoration: underline;
        }

        /* 图片样式 */
        img {
          max-width: 100%;
          height: auto;
          page-break-inside: avoid;
        }

        /* Mermaid图表样式 */
        .mermaid {
          text-align: center;
          margin: 20px 0;
          page-break-inside: avoid;
        }

        .mermaid svg {
          max-width: 100%;
          height: auto;
        }

        /* 分页控制 */
        .page-break {
          page-break-before: always;
        }

        /* 打印优化 */
        @media print {
          body {
            -webkit-print-color-adjust: exact;
            color-adjust: exact;
          }
          
          .mermaid {
            page-break-inside: avoid;
          }
          
          pre {
            page-break-inside: avoid;
          }
          
          table {
            page-break-inside: avoid;
          }
        }

        /* 响应式设计 */
        @page {
          margin: ${this.options.margin.top} ${this.options.margin.right} ${this.options.margin.bottom} ${this.options.margin.left};
        }
      </style>
    `;
  }

  /**
   * 生成HTML内容
   */
  private async generateHtml(markdownContent: string, title = 'Document'): Promise<string> {
    if (!this.md) {
      await this.initializeMarkdownIt();
    }

    const htmlContent = this.md.render(markdownContent);

    return `
      <!DOCTYPE html>
      <html lang="zh-CN">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>${title}</title>
        ${this.generateStyles()}
        ${await LocalMermaidManager.generateMermaidScript(
          this.options.mermaidTheme,
          this.options.chineseFont
        )}
      </head>
      <body class="chinese">
        ${htmlContent}
      </body>
      </html>
    `;
  }

  /**
   * 转换Markdown为PDF
   */
  async convertToPdf(
    markdownContent: string,
    outputPath: string,
    options: ConversionOptions = {}
  ): Promise<ConversionResult> {
    const convertOptions = { ...this.options, ...options };
    const title = convertOptions.title || path.basename(outputPath, '.pdf');

    try {
      // 生成HTML内容
      const html = await this.generateHtml(markdownContent, title);

      // 使用PdfBrowserManager生成PDF
      const pdfBuffer = await this.browserManager.generatePdf(html, outputPath, {
        format: convertOptions.format,
        margin: convertOptions.margin,
        displayHeaderFooter: convertOptions.displayHeaderFooter,
        printBackground: convertOptions.printBackground,
        preferCSSPageSize: convertOptions.preferCSSPageSize,
        landscape: convertOptions.landscape,
      });

      // 额外日志：确认buffer大小
      this.log.info(`[PDF] 生成完成，大小: ${pdfBuffer.length} bytes -> ${outputPath}`);

      return {
        success: true,
        outputPath,
        size: pdfBuffer.length,
        message: `PDF生成成功: ${outputPath}`,
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      this.log.error('PDF生成失败:', errorMessage);
      throw new Error(`PDF生成失败: ${errorMessage}`);
    }
  }

  /**
   * 从文件转换
   */
  async convertFromFile(
    markdownFilePath: string,
    outputPath: string,
    options: ConversionOptions = {}
  ): Promise<ConversionResult> {
    try {
      const markdownContent = await fs.readFile(markdownFilePath, 'utf8');
      const title = options.title || path.basename(markdownFilePath, '.md');

      return await this.convertToPdf(markdownContent, outputPath, { ...options, title });
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      throw new Error(`读取Markdown文件失败: ${errorMessage}`);
    }
  }
}

/**
 * 便捷函数：直接转换Markdown内容为PDF
 */
export async function markdownToPdf(
  markdownContent: string,
  outputPath: string,
  options: PdfOptions & ConversionOptions = {}
): Promise<ConversionResult> {
  const converter = new MarkdownToPdf(options);
  return await converter.convertToPdf(markdownContent, outputPath, options);
}

/**
 * 便捷函数：从文件转换为PDF
 */
export async function markdownFileToPdf(
  markdownFilePath: string,
  outputPath: string,
  options: PdfOptions & ConversionOptions = {}
): Promise<ConversionResult> {
  const converter = new MarkdownToPdf(options);
  return await converter.convertFromFile(markdownFilePath, outputPath, options);
}
